import React, { InputHTMLAttributes, forwardRef } from 'react';
import classNames from 'classnames';

/**
 * Input 组件尺寸枚举
 * 定义输入框的可用尺寸选项
 */
export enum InputSize {
  /** 大尺寸输入框 */
  lg = 'lg',
  /** 默认尺寸输入框 */
  default = 'default',
  /** 小尺寸输入框 */
  sm = 'sm',
}

/**
 * Input 组件类型枚举
 * 定义输入框的可用类型选项
 */
export enum InputType {
  /** 文本输入框 */
  text = 'text',
  /** 密码输入框 */
  password = 'password',
  /** 数字输入框 */
  number = 'number',
  /** 邮箱输入框 */
  email = 'email',
  /** 电话输入框 */
  tel = 'tel',
  /** URL输入框 */
  url = 'url',
  /** 搜索输入框 */
  search = 'search',
}

/**
 * Input 组件基础属性接口
 * 定义 Input 组件接收的所有属性
 */
export interface BaseInputProps {
  /** 自定义 CSS 类名 */
  className?: string;
  /** 设置输入框是否禁用 */
  disabled?: boolean;
  /** 设置输入框尺寸 */
  size?: InputSize;
  /** 设置输入框类型 */
  type?: InputType;
  /** 输入框占位符文本 */
  placeholder?: string;
  /** 输入框前缀图标或文本 */
  prefix?: string | React.ReactElement;
  /** 输入框后缀图标或文本 */
  suffix?: string | React.ReactElement;
  /** 输入框值 */
  value?: string;
  /** 输入框默认值 */
  defaultValue?: string;
  /** 输入变化回调函数 */
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
  /** 输入框聚焦回调函数 */
  onFocus?: (e: React.FocusEvent<HTMLInputElement>) => void;
  /** 输入框失焦回调函数 */
  onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
  /** 输入框按键回调函数 */
  onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
  /** 输入框按键抬起回调函数 */
  onKeyUp?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
  /** 输入框自动聚焦 */
  autoFocus?: boolean;
  /** 输入框只读 */
  readOnly?: boolean;
  /** 输入框最大长度 */
  maxLength?: number;
  /** 输入框最小长度 */
  minLength?: number;
  /** 输入框名称 */
  name?: string;
  /** 输入框ID */
  id?: string;
  /** 输入框标签 */
  label?: React.ReactNode;
  /** 错误状态 */
  error?: boolean;
  /** 错误提示信息 */
  errorMessage?: string;
  /** 成功状态 */
  success?: boolean;
  /** 警告状态 */
  warning?: boolean;
}

/**
 * 原生输入框属性接口
 * 继承 BaseInputProps 的所有属性，并额外合并了所有标准的 HTML <input> 元素属性
 * 使用 Omit 排除掉原生的 size 属性，避免与自定义的 size 属性冲突
 */
type NativeInputProps = BaseInputProps & Omit<InputHTMLAttributes<HTMLElement>, 'size'>;

/**
 * 最终导出的 Input 组件属性类型
 * 使用 Partial 工具类型，将 NativeInputProps 的所有属性变为可选
 */
export type InputProps = Partial<NativeInputProps>;

/**
 * Input 输入框组件
 * 
 * 这是一个高度可定制的输入框组件，支持多种类型、尺寸、状态和前后缀。
 * 组件会根据传入的属性自动生成相应的 CSS 类名和样式。
 * 
 * @example
 * ```tsx
 * // 基本使用
 * <Input placeholder="请输入内容" />
 * 
 * // 带前缀的输入框
 * <Input prefix="¥" placeholder="请输入金额" />
 * 
 * // 带后缀的输入框
 * <Input suffix="@example.com" placeholder="用户名" />
 * 
 * // 禁用状态
 * <Input disabled placeholder="禁用输入框" />
 * 
 * // 错误状态
 * <Input error errorMessage="请输入有效内容" />
 * ```
 * 
 * @param props - 输入框属性
 * @returns 渲染的输入框元素
 */
export const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
  const {
    className,
    disabled = false,
    size = InputSize.default,
    type = InputType.text,
    placeholder,
    prefix,
    suffix,
    value,
    defaultValue,
    onChange,
    onFocus,
    onBlur,
    onKeyDown,
    onKeyUp,
    autoFocus,
    readOnly,
    maxLength,
    minLength,
    name,
    id,
    label,
    error = false,
    errorMessage,
    success = false,
    warning = false,
    ...restProps
  } = props;

  /**
   * 生成输入框的 CSS 类名
   * 使用 classnames 库动态生成类名：
   * - 基础类名: "input"
   * - 尺寸类名: "input-{size}"（如 "input-lg"）
   * - 状态类名: "input-disabled", "input-error", "input-success", "input-warning"
   * - 自定义类名: 用户传入的 className
   */
  const classes = classNames('input', className, {
    [`input-${size}`]: size && size !== InputSize.default, // 动态生成尺寸类名
    'input-disabled': disabled, // 禁用状态类名
    'input-error': error, // 错误状态类名
    'input-success': success, // 成功状态类名
    'input-warning': warning, // 警告状态类名
    'input-with-prefix': prefix, // 有前缀类名
    'input-with-suffix': suffix, // 有后缀类名
  });

  /**
   * 渲染输入框包装器
   * 包含标签、输入框、前后缀和错误信息
   */
  return (
    <div className="input-wrapper">
      {/* 输入框标签 */}
      {label && (
        <label htmlFor={id} className="input-label">
          {label}
        </label>
      )}
      
      {/* 输入框容器 */}
      <div className="input-container">
        {/* 前缀内容 */}
        {prefix && (
          <span className="input-prefix">
            {prefix}
          </span>
        )}
        
        {/* 输入框主体 */}
        <input
          ref={ref}
          className={classes}
          type={type}
          placeholder={placeholder}
          value={value}
          defaultValue={defaultValue}
          disabled={disabled}
          readOnly={readOnly}
          autoFocus={autoFocus}
          maxLength={maxLength}
          minLength={minLength}
          name={name}
          id={id}
          onChange={onChange}
          onFocus={onFocus}
          onBlur={onBlur}
          onKeyDown={onKeyDown}
          onKeyUp={onKeyUp}
          {...restProps}
        />
        
        {/* 后缀内容 */}
        {suffix && (
          <span className="input-suffix">
            {suffix}
          </span>
        )}
      </div>
      
      {/* 错误提示信息 */}
      {error && errorMessage && (
        <div className="input-error-message">
          {errorMessage}
        </div>
      )}
    </div>
  );
});

Input.displayName = 'Input';

export default Input;